<?php
/**
 * @author zhangrui
 */

namespace App\Common\RabbitMQ;


use SebastianBergmann\CodeCoverage\Report\PHP;

class AbstractAMQP
{
    /** @var \AMQPConnection  */
    protected $conn;
    /** @var bool 使用持久连接 */
    protected $persistent = false;

    /** @var \AMQPChannel */
    protected $ch;

    /** @var \AMQPExchange */
    protected $ex;
    /**
     * @var string 交换类型
     * 可选值:
     * AMQP_EX_TYPE_DIRECT
     * AMQP_EX_TYPE_FANOUT
     * AMQP_EX_TYPE_TOPIC
     * AMQP_EX_TYPE_HEADERS
     */
    protected $exType = AMQP_EX_TYPE_DIRECT;
    /** @var string 交换名称 */
    protected $exName = 'test.direct';
    /**
     * @var int 交换标志
     * 可选值
     * AMQP_DURABLE
     * AMQP_PASSIVE
     */
    protected $exFlags = AMQP_DURABLE;
    /** @var array 交换参数 */
    protected $exArguments = [];
    /** @var bool 主动申明交换 */
    protected $declareEx = false;

    /**
     * AbstractAMQP constructor.
     * @param bool $persistent 使用持久连接
     * @throws \AMQPChannelException
     * @throws \AMQPConnectionException
     * @throws \AMQPExchangeException
     */
    public function __construct(bool $persistent = false)
    {
        $this->persistent = $persistent;
        $this->conn = $this->newConnection();
        $this->ch = $this->newChannel($this->conn);
        $this->ex = $this->newExchange($this->ch);
    }

    /**
     * @return \AMQPConnection
     * @throws \AMQPConnectionException
     */
    protected function newConnection()
    {
        $conn = ConnectFactory::getConnect(config('AMQP.api'));
        if ($this->persistent) {
            $conn->pconnect();
        } else {
            $conn->connect();
        }
        return $conn;
    }

    /**
     * @return \AMQPConnection
     */
    public function getConnection()
    {
        if (! $this->conn->isConnected()) {
            $this->reconnection();
        }
        return $this->conn;
    }

    public function reconnection()
    {
        if (! $this->conn->isConnected()) {
            if ($this->persistent) {
                $this->conn->preconnect();
            } else {
                $this->conn->reconnect();
            }
        }
    }

    /**
     * @return \AMQPChannel
     * @throws \AMQPConnectionException
     */
    protected function newChannel(\AMQPConnection $connection)
    {
        return new \AMQPChannel($connection);
    }

    /**
     * @return \AMQPChannel
     */
    public function getChannel()
    {
        if (! $this->ch->isConnected()) {
            $this->ch = $this->newChannel($this->getConnection());
        }
        return $this->ch;
    }

    /**
     * @param \AMQPChannel $channel
     * @return \AMQPExchange
     * @throws \AMQPChannelException
     * @throws \AMQPConnectionException
     * @throws \AMQPExchangeException
     */
    protected function newExchange(\AMQPChannel $channel)
    {
        $ex = new \AMQPExchange($channel);
        $ex->setType($this->exType);
        $ex->setName($this->exName);
        $ex->setFlags($this->exFlags);
        if ($this->exArguments) {
            $ex->setArguments($this->exArguments);
        }
        if ($this->declareEx) {
            $ex->declareExchange();
        }
        return $ex;
    }

    /**
     * @return \AMQPExchange
     */
    public function getExchange()
    {
        if (! $this->ch->isConnected() || ! $this->conn->isConnected()) {
            $this->ex = $this->newExchange($this->getChannel());
        }
        return $this->ex;
    }

    public function __destruct()
    {
        if ($this->conn && $this->conn->isConnected()) {
            if ($this->persistent) {
                $this->conn->pdisconnect();
            } else {
                $this->conn->disconnect();
            }

            if ($this->ch->isConnected()) {
                $this->ch->close();
            }
        }
    }
}
